﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CommonLib {
    public class Sphere : Primitive {
        private Vector3c position;
        private double radius, rsq;
        private Cell boundingBox;

        public Sphere(Vector3c pos, double rad, bool li) {
            this.position = pos;
            this.radius = rad;
            this.rsq = rad * rad;
            this.light = li;
            this.material = Material;
            Vector3c bbPos = pos;
            bbPos.sub(rad);
            this.boundingBox = new Cell(bbPos, new Vector3c(2 * rad, 2 * rad, 2 * rad));
        }
        public override Orientation isIntersect(Ray r, ref double dist) {
            // dot = (V, Vo - Po)
            // d = dot^2 - |Vo - Po|^2 + r^2 >= 0
            // t- = -dot - Sqrt(d)
            // t+ = -dot + Sqrt(d)
            // P = tV * Vo

            Vector3c v = r.position;
            v.x -= position.x;
            v.y -= position.y;
            v.z -= position.z;

            var p = r.direction;
            double dot = (p.x * v.x) + (p.y * v.y) + (p.z * v.z);
            double vv = (v.x * v.x) + (v.y * v.y) + (v.z * v.z);
            double d = (dot * dot) - vv + (radius * radius);

            if ((d > DoubleTester.Epsilon) == false)
                return 0.0;

            d = Math.Sqrt(d);
            double tneg = -dot - d;
            double tpos = -dot + d;
            if (DoubleTester.Epsilon < tpos) {
                if (DoubleTester.Epsilon < tneg && tneg < dist) {
                    dist = tneg;
                    return Orientation.Exterior;
                }
                if (tneg < DoubleTester.Epsilon && tpos < dist) {
                    dist = tpos;
                    return Orientation.Interior;
                }
            }

            return Orientation.Nonexistent;
        }
        public override Vector3c getNormal(Vector3c bndry) {
            Vector3c normal = bndry;
            normal.sub(position);
            normal.normalize();
            return normal;
        }
        public override Cell getBoundingBox() {
            return boundingBox;
        }
        public override Intersection isIntersect(Cell b) {
            double d = 0;
            double diff;
            if ((diff = position.x - b.vmax.x) > 0)
                d += diff * diff;
            else if ((diff = b.vmin.x - position.x) > 0)
                d += diff * diff;
            if ((diff = position.y - b.vmax.y) > 0)
                d += diff * diff;
            else if ((diff = b.vmin.y - position.y) > 0)
                d += diff * diff;
            if ((diff = position.z - b.vmax.z) > 0)
                d += diff * diff;
            else if ((diff = b.vmin.z - position.z) > 0)
                d += diff * diff;

            if (d > rsq)
                return Intersection.Outside;
            return Intersection.Intersecting;
        }
        public override Vector3c getCenter() {
            return position;
        }
    }
}
